package site.hanzhe.config;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import site.hanzhe.constant.CrowdConstant;
import site.hanzhe.exception.AccessForbiddenException;
import site.hanzhe.exception.AdminAcctExistsException;
import site.hanzhe.exception.AdminDeleteException;
import site.hanzhe.exception.LoginFailedException;
import site.hanzhe.utils.CrowdUtil;
import site.hanzhe.utils.R;
import org.springframework.security.access.AccessDeniedException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 全局异常处理类
 */
@Slf4j
@ControllerAdvice
public class ResolverControllerExceptionConfig {

    private final String ERROR_PAGE = "error";        // 异常视图名称
    private final String ADMIN_LOGIN_PAGE = "admin-login";  // 登录视图名称
    private final String ADMIN_ADD_PAGE = "admin-add";  // 登录视图名称

    // 登录失败的异常处理
    @ExceptionHandler(LoginFailedException.class)
    public ModelAndView inFailedException(HttpServletRequest req, HttpServletResponse resp, LoginFailedException e){
        return this.common(req, resp, e, this.ADMIN_LOGIN_PAGE);
    }

    // 访问权限不足异常处理
    @Deprecated  // 在使用Security之后，登录被接管之后这个方法就用不上了
    @ExceptionHandler(AccessForbiddenException.class)
    public ModelAndView resolverAccessForbiddenException(HttpServletRequest req, HttpServletResponse resp, AccessForbiddenException e){
        return this.common(req, resp, e, this.ERROR_PAGE);
    }

    // 管理员删除自己本身时的异常处理
    @ExceptionHandler(AdminDeleteException.class)
    public ModelAndView resolverAdminDeleteException(HttpServletRequest req, HttpServletResponse resp, AdminDeleteException e){
        return this.common(req, resp, e, this.ERROR_PAGE);
    }

    // 管理员账号重复的异常
    @ExceptionHandler(AdminAcctExistsException.class)
    public ModelAndView resolverAdminAcctExistsException(HttpServletRequest req, HttpServletResponse resp, AdminAcctExistsException e){
        return this.common(req, resp, e, this.ADMIN_ADD_PAGE);
    }

    // 没有访问权限：专门捕获Security的403异常
    @ExceptionHandler(AccessDeniedException.class)
    public ModelAndView resolverAccessDeniedException(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException e){
        return this.common(req, resp, new RuntimeException(CrowdConstant.MESSAGE_ACCESS_403), this.ERROR_PAGE);
    }







    // 上面抓不住的异常会被Exception抓住
    @ExceptionHandler(Exception.class)
    public ModelAndView resolverRuntimeException(HttpServletRequest req, HttpServletResponse resp, Exception e){
        log.info("没抓住的异常==>>" + e.getClass().getName());
        return this.common(req, resp, e, this.ERROR_PAGE);
    }

    // 抽取复用方法
    public ModelAndView common(HttpServletRequest req, HttpServletResponse resp, Exception e, String page){
        log.info("【common】==>>" + e.getClass().getName());
        if (CrowdUtil.isAjax(req)){
            // 如果是AJAX请求就获取到异常信息封装到返回模板中转换JSON字符串响应给客户端
            try {
                String json = new Gson().toJson(R.error(e.getMessage()));
                resp.getWriter().write(json);
                return null;
            } catch (IOException ex) { }
            return null;
        }
        // 如果走到这说明不是AJAX请求，在这里就可以配置跳转异常页面传递异常信息
        ModelAndView mv = new ModelAndView();
        mv.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, e);
        mv.setViewName(page);
        return mv;
    }

}